package com.audaque.encoding.controller;

import com.audaque.encoding.common.Result;
import com.audaque.encoding.mapper.CallbackMapper;
import com.audaque.encoding.model.*;
import com.audaque.encoding.service.CoreService;
import com.audaque.encoding.service.IEncodingService;
import com.audaque.encoding.util.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author mayong
 * @since 2024/3/20
 * <p>
 * <p>
 * 文件上传
 */
@RestController
@Slf4j
public class FileController {

    @Resource
    private CoreService coreService;
    @Autowired
    private IEncodingService encodingService;

    @Resource
    private CallbackMapper callbackMapper;

    @PostMapping("upload/excel")
    public String uploadFile(@RequestPart(value = "file") MultipartFile file) {
        List<byte[]> chunks = null;
        GetFilepathRes filePath = null;
        String filename = null;
        try {
            filename = file.getOriginalFilename();
            chunks = chunk(file);
            GetFilepathReq build = GetFilepathReq.builder()
                    .chunkCount(chunks.size())
                    .fileName(filename)
                    .build();

            // 01
            filePath = coreService.getFilePath(build);
            encodingService.insertEncodingLog(EncodingLog.builder()
                    .fileId(filePath.getId())
                    .log("获取分片上传文件路径，成功")
                    .build());
            encodingService.insertEncodingHistory(
                    EncodingHistory.builder().fileId(filePath.getId())
                            .createTime(LocalDateTime.now())
                            .status("获取分片上传文件路径，成功")
                            .fileName(filename)
                            .build()
            );
        } catch (Exception e) {
            encodingService.insertEncodingHistory(
                    EncodingHistory.builder().fileId(filePath == null ? null : filePath.getId())
                            .createTime(LocalDateTime.now())
                            .remark(e.getMessage())
                            .status("获取分片上传文件路径，失败")
                            .fileName(filename)
                            .build()
            );
            throw e;
        }

        List<byte[]> finalChunks = chunks;
        GetFilepathRes finalFilePath = filePath;
        String finalFilename = filename;
        new Thread(() -> otherStep(finalChunks, finalFilePath, finalFilename)).start();
        return filePath.getId();
    }

    protected void otherStep(List<byte[]> chunks, GetFilepathRes filePath, String filename) {
        try {
            log.info("开始异步执行");
            // 02
            for (int i = 0; i < chunks.size(); i++) {
                coreService.chunkUpload(filePath.getUploadUrls()[i], chunks.get(i));
            }
            encodingService.insertEncodingLog(EncodingLog.builder()
                    .fileId(filePath.getId())
                    .log("分片上传成功")
                    .build());

            //03
            coreService.merge(filePath.getId());
            encodingService.insertEncodingLog(EncodingLog.builder()
                    .fileId(filePath.getId())
                    .log("分片合并请求成功")
                    .build());
            //04
            String s = coreService.codeTask(filePath.getId());
            encodingService.insertEncodingLog(EncodingLog.builder()
                    .fileId(filePath.getId())
                    .log("赋码请求成功，任务id: " + s)
                    .build());

            encodingService.insertEncodingHistory(
                    EncodingHistory.builder().fileId(filePath.getId())
                            .createTime(LocalDateTime.now())
                            .status("赋码请求成功")
                            .fileName(filename)
                            .build());
        } catch (Exception e) {
            encodingService.insertEncodingHistory(
                    EncodingHistory.builder().fileId(filePath.getId())
                            .createTime(LocalDateTime.now())
                            .remark(e.getMessage())
                            .status("赋码请求失败")
                            .fileName(filename)
                            .build());
            throw e;
        }

    }

    @GetMapping("code/re-call-back")
    public Result<Void> reCall(String noticeId){

        CallbackDO one = callbackMapper.getOne(noticeId);
        if (one == null) {
            return Result.failure();
        }
        String json = one.getJson();
        CallbackDTO dto = coreService.object(json, CallbackDTO.class);
        save(dto);
        return Result.success();
    }



    String[] exc = {"fm_社管网格_0411.xlsx"};

    @Resource(name = "restTemplateIgnoreSSL")
    private RestTemplate restTemplateIgnoreSSL;

    String dir = "C:/Users/Administrator/Desktop/daye3";
    @GetMapping("code/auto-re")
    public void autoReCall(){
        List<String> names = Arrays.asList(exc);
        List<CallbackDO> list = callbackMapper.list();
        for(CallbackDO callbackDO :list){
            String json = callbackDO.getJson();
            CallbackDTO dto = coreService.object(json, CallbackDTO.class);
            try {
                FileInfoRes info = coreService.info(dto.getContent().getFileId());
                if(names.contains(info.getFileName())){
                    System.err.println(info.getFileName() + " : " + info.getChunks().get(0).getUrl());
//                    callbackMapper.save(coreService.json(info),callbackDO.getNoticeId());
                    coreService.downLoad(info.getChunks().get(0).getUrl(),dir + "/"+ info.getFileName());
                    System.out.println();
                }
            }catch (Exception e){
                log.error(dto.getContent().getFileId());
            }
        }
    }



    @PostMapping("code/call-back")
    public void call(@RequestBody CallbackDTO dto) {
        log.info("------------------------------接收到赋码成功的回调信息----------------------------------");
        String json = coreService.json(dto);
        log.info("回调实体信息： " + json);
        synchronized (FileController.class) {
            CallbackDO one = callbackMapper.getOne(dto.getId());
            if (one == null) {
                callbackMapper.insert(CallbackDO.builder()
                        .noticeId(dto.getId())
                        .json(json)
                        .createTime(LocalDateTime.now())
                        .build());
                encodingService.insertEncodingLog(EncodingLog.builder()
                        .fileId(dto.getId())
                        .log("接收到赋码回调通知, 回调内容: " + json)
                        .build());
                new Thread(() -> save(dto)).start();
            } else {
                log.error("该回调消息已经被处理。");
            }
        }
    }


    protected void save(CallbackDTO dto) {
        // TODO 回调接口中未返回原始上传的文件id，这块的日志没有办法和之前的日志映射
        FileInfoRes info = null;
        try {
            List<byte[]> res = new ArrayList<>();
            if (Objects.equals(dto.getType(), "CODE_ALL")
                    || Objects.equals(dto.getType(), "CODE_CODED")
                    || Objects.equals(dto.getType(), "CODE_UNCODED")) {
                // 05
                info = coreService.info(dto.getContent().getFileId());
                List<FileInfoRes.Chunk> chunks = info.getChunks();
                for (FileInfoRes.Chunk chunk : chunks) {
                    // 06
                    byte[] bytes = coreService.downLoad(chunk.getUrl());
                    res.add(bytes);
                }
                log.info("执行保存逻辑");
                encodingService.saveEncoding(res, info.getFileName());
                log.info("数据保存成功");
                encodingService.insertEncodingLog(EncodingLog.builder()
                        .fileId(dto.getId())
                        .log("数据落库成功")
                        .build());
                encodingService.insertEncodingHistory(
                        EncodingHistory.builder().fileId(dto.getId())
                                .createTime(LocalDateTime.now())
                                .status("数据落库成功")
                                .fileName(info.getFileName())
                                .build());

            }
        } catch (Exception e) {
            encodingService.insertEncodingHistory(
                    EncodingHistory.builder().fileId(dto.getId())
                            .createTime(LocalDateTime.now())
                            .status("数据落库失败")
                            .fileName(info == null ? null : info.getFileName())
                            .build());
            throw e;
        }

    }

    private List<byte[]> chunk(MultipartFile file) {
        log.info("执行大文件分片逻辑");
        try {
            return ExcelUtil.sharding(file.getBytes(), 5);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
